/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _OLA_PAL_SOCKET_H_
#define _OLA_PAL_SOCKET_H_

#define OLA_MULTICAST_GROUP_ADDR4   "238.238.238.238"

#define OLA_SOCKET_AF_INET  2

#define OLA_SOCKET_INADDR_ANY     ((uint32_t)0x00000000UL)

typedef enum {
    OLA_SOCKET_TYPE_TCP = 0,
    OLA_SOCKET_TYPE_UDP,
} OlaSocketType;

typedef enum {
    OLA_SOCKET_OPTION_JOIN_MULTI_GROUP,
    OLA_SOCKET_OPTION_REMOVE_MULTI_GROUP,
    OLA_SOCKET_OPTION_ENABLE_BROADCAST,
    OLA_SOCKET_OPTION_ENABLE_REUSEADDR,
    OLA_SOCKET_OPTION_READ_TIMEOUT,
    OLA_SOCKET_OPTION_SEND_TIMEOUT,
} OlaSocketOption;

typedef struct {
    unsigned short saFamily;
#define OLA_SA_DATA_LEN     14
    char saData[OLA_SA_DATA_LEN];
} OlaSockaddr;

typedef struct {
    unsigned short sinFamily;
    unsigned short sinPort;
    unsigned int sinAddr;
#define OLA_SIN_ZERO_LEN    8
    char sinZero[OLA_SIN_ZERO_LEN];
} OlaSockaddrIn;

typedef struct OlaAddrInfo OlaAddrInfo;

struct OlaAddrInfo {
    int aiFlags;
    int aiFamily;
    int aiSocktype;
    int aiProtocol;
    int aiAddrlen;
    OlaSockaddr *aiAddr;
    char *aiCanonname;
    OlaAddrInfo *aiNext;
};

typedef struct {
    int *fdSet;
    unsigned short num;
} OlaFdSet;

typedef enum {
    OLA_SOCKET_ERROR_NO_ERROR = 0,
    OLA_SOCKET_ERROR_EAGAIN,
    OLA_SOCKET_ERROR_EINTR,
    OLA_SOCKET_ERROR_EINPROGRESS,
    OLA_SOCKET_ERROR_OTHER,
} OlaSocketErrorCode;

/*
 * 功能: 将主机名转换为地址信息
 * 参数: nodename，主机名
 *       servname，服务名
 *       hints，指定参数
 *       result，出参，地址信息链表
 * 返回: 0，获取成功
 *       -1，获取失败
 */
int OlaGetAddrInfo(const char *nodename, const char *servname,
    const OlaAddrInfo *hints, OlaAddrInfo **result);

/*
 * 功能: 释放OlaPalGetAddrInfo获取的地址信息链表
 * 参数: addrInfo，地址信息链表
 */
void OlaFreeAddrInfo(OlaAddrInfo *addrInfo);

/*
 * 功能: 获取获取INET网络套接字文件描述符
 * 参数: type，指定协议类型
 * 返回: 大于等于0，返回套接字描述符
 *       -1，获取失败
 * 注意: 返回的文件描述符需设置为非阻塞
 */
int OlaSocket(OlaSocketType type);

/*
 * 功能: 关闭套接字
 * 参数: fd，指定套接字
 * 返回: 0，关闭成功
 *       -1，关闭失败
 */
int OlaClose(int fd);

/*
 * 功能: 设置套接字可选字段
 * 参数: fd，指定套接字
 *       option，设定的选项
 *       param，选项参数
 * 返回: 0，设置成功
 *       -1，设置失败
 */
int OlaSetSocketOpt(int fd, OlaSocketOption option, const void *param);

/*
 * 功能: 绑定套接字
 * 参数: fd，指定的套接字
 *       addr，指向包含要绑定到套接字的地址
 * 返回: 0，绑定成功
 *       -1，绑定失败
 */
int OlaBind(int fd, const OlaSockaddr *addr);

/*
 * 功能: 连接对端IP地址
 * 参数: fd，指定的套接字文件描述符
 *       addr，指向套接字连接的地址
 * 返回: 0，设置成功
 *       -1，设置失败
 */
int OlaConnect(int fd, const OlaSockaddr *addr);

/*
 * 功能: 从已经连接的套接字接收消息
 * 参数: fd，指定的套接字
 *       buf，接收数据缓冲区
 *       len，缓冲区长度
 * 返回: 大于等于0，实际接收的字节数
 *       小于0，读取出错
 */
int OlaRecv(int fd, unsigned char *buf, unsigned short len);

/*
 * 功能: 传输指定长度消息到对端
 * 参数: fd，指定的套接字
 *       buf，要发送的数据
 *       len，数据长度
 * 返回: 大于等于0，实际发送的字节数
 *       小于0，发送失败
 */
int OlaSend(int fd, const unsigned char *buf, unsigned short len);

/*
 * 功能: 从套接字接收消息，并返回源地址
 * 参数: fd，指定的套接字
 *       buf，接收数据缓冲区
 *       len，缓冲区长度
 *       from，出参，数据源地址
 * 返回: 大于等于0，实际接收的字节数
 *       小于0，接收出错
 */
int OlaRecvFrom(int fd, unsigned char *buf, unsigned short len, OlaSockaddr *from);

/*
 * 功能: 发送数据到指定地址
 * 参数: fd，指定的套接字
 *       buf，要发送的数据
 *       len，数据长度
 *       to，目标地址信息
 * 返回: 大于0，实际发送的字节数
 *       小于等于0，发送失败
 */
int OlaSendTo(int fd, const unsigned char *buf, unsigned short len, const OlaSockaddr *to);

/*
 * 功能: 检视多个文件描述符
 * 参数: readSet，待检查是否准备好读取的描述符
 *       writeSet，待检查是否准备好写入的描述符
 *       except，待检查挂起错误条件的描述符
 *       timeoutMs，超时时间
 * 返回: 大于0，与条件相符的描述符数量
 *       等于0，超时
 *       小于0，套接字出错
 * 注意: 返回时需将不符合要求的描述符置为-1
 */
int OlaSelect(OlaFdSet *readSet, OlaFdSet *writeSet, OlaFdSet *exceptSet, unsigned int timeoutMs);

/*
 * 功能: 获取描述符错误码
 * 参数: fd，指定的套接字
 * 返回: 错误码
 */
OlaSocketErrorCode OlaGetSocketError(int fd);

/*
 * 功能: 将32位的主机序转为网络序
 * 参数: hostlong，32位主机序
 * 返回: 32位网络序
 */
unsigned int OlaHtonl(unsigned int hostlong);

/*
 * 功能: 将32位的网络序转为主机序
 * 参数: netlong，32位网络序
 * 返回: 32位主机序
 */
unsigned int OlaNtohl(unsigned int netlong);

/*
 * 功能: 将16位的主机序转为网络序
 * 参数: hostlong，16位主机序
 * 返回: 16位网络序
 */
unsigned short OlaHtons(unsigned short hostshort);

/*
 * 功能: 将16位的网络序转为主机序
 * 参数: netlong，16位网络序
 * 返回: 16位主机序
 */
unsigned short OlaNtohs(unsigned short netshort);

/*
 * 功能: 将点分ip地址字符串转为32位网络序地址
 * 参数: ip，点分ip地址字符串
 *       addr，出参，32位网络序地址
 * 返回: 0，转换失败
 *       非0，转换成功
 */
int OlaInetAton(const char *ip, unsigned int *addr);

/*
 * 功能: 将32位网络序地址转为点分ip地址字符串
 * 参数: addr，32位网络序地址
 * 返回: NULL，转换失败
 *       非NULL，转换成功
 */
char *OlaInetNtoa(unsigned int addr);

/*
 * 功能: 将点分ip地址字符串转为32位网络序地址
 * 参数: ip，点分ip地址字符串
 *       addr，出参，32位网络序地址
 * 返回: 0xFFFFFFFF，转换失败
 *       其他，转换成功
 */
unsigned int OlaInetAddr(const char *ip);

#endif /* _OLA_PAL_SOCKET_H_ */